home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Hacks / Hacks ’96 / Talking Telnet / source / parse / parse.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-22  |  23.5 KB  |  917 lines  |  [TEXT/CWIE]

  1. /****************************************************************
  2. *    NCSA Telnet for the Macintosh                                *
  3. *                                                                *
  4. *    National Center for Supercomputing Applications                *
  5. *    Software Development Group                                    *
  6. *    152 Computing Applications Building                            *
  7. *    605 E. Springfield Ave.                                        *
  8. *    Champaign, IL  61820                                        *
  9. *                                                                *
  10. *    Copyright (c) 1986-1994,                                    *
  11. *    Board of Trustees of the University of Illinois                *
  12. ****************************************************************/
  13.  
  14. #ifdef MPW
  15. #pragma segment Parse
  16. #endif
  17.  
  18.  
  19. #include "parse.h"                // For our #defines
  20. #include "wind.h"                /* For WindRec structure */
  21.                 /* For putln proto */
  22.  
  23. #include "network.proto.h"                /* For net functions */
  24. #include "linemode.proto.h"
  25. #include "vgtek.proto.h"
  26. #include "vsdata.h"
  27. #include "vsinterf.proto.h"
  28. #include "maclook.proto.h"
  29. #include "tekrgmac.proto.h"
  30. #include "menuseg.proto.h"
  31. #include "translate.proto.h"
  32. #include "vr.h"
  33. #include "vr.proto.h"
  34. #include "tnae.h"
  35. #include "authencrypt.h"
  36. #include "authencrypt.proto.h"
  37. #include "wdefpatch.proto.h"
  38. #include "speech.proto.h"
  39.  
  40. //#define    OPTS_DEBUG
  41. #ifdef    OPTS_DEBUG
  42. #include "optsdebug.h"
  43. #define    opts_debug_print(x)    putln(x)    
  44. static char munger[255];
  45. #else
  46. #define    opts_debug_print(x)
  47. #endif
  48.  
  49. #include "Profiler.h"
  50.  
  51. extern short     scrn;
  52. extern WindRec    *screens;
  53.  
  54. #include "parse.proto.h"
  55.  
  56. static    char    *getcname(struct WindRec *tw);
  57. static    void    encryptStatechange(struct WindRec *tw);
  58. static    void    process_suboption(struct WindRec *tw, unsigned char *start, unsigned char *end);
  59. static    void    send_will(short port, short option);
  60. static    void    send_wont(short port, short option);
  61. static    void    telnet_do(struct WindRec *tw, short option);
  62. static    void    telnet_dont(struct WindRec *tw, short option);
  63. static    void    telnet_will(struct WindRec *tw, short option);
  64. static    void    telnet_wont(struct WindRec *tw, short option);
  65.  
  66. void    Parseunload(void) {}
  67.  
  68. void    SendStringAsIfTyped(struct WindRec *tw, char *string, short len)
  69. {
  70.     trbuf_nat_mac((unsigned char *)string, len, tw->national);
  71.  
  72.     netpush(tw->port);
  73.  
  74.     if (tw->kblen > 0) {     /* need to flush buffer */
  75.         netwrite(tw->port, tw->kbbuf, tw->kblen);
  76.         tw->kblen=0;
  77.     }
  78.  
  79.     netwrite(tw->port, string, len);
  80.  
  81.     if (tw->echo)
  82.         parse(tw, (unsigned char *)string, len);
  83. }
  84.  
  85. /*********************************************************************/
  86. /*  parse
  87. *   look at the string which has just come in from outside and
  88. *   check for special sequences that we are interested in.
  89. *
  90. *   Tries to pass through routine strings immediately, waiting for special
  91. *   characters ESC and 255 to change modes.
  92. */
  93.  
  94. void parse (struct WindRec *tw, unsigned char *st, short cnt)
  95. {
  96.     short i,temptw;
  97.     unsigned char *mark,*orig;
  98.  
  99. //    ProfilerSetStatus(true);
  100.  
  101.     orig = st;                /* remember beginning point */
  102.     mark = st + cnt;        /* set to end of input string */
  103. /*
  104. * raw mode for debugging, passes through escape sequences and other
  105. * special characters as <27> symbols
  106. */
  107.     if (tw->termstate == DUMBTYPE)
  108.         {
  109.         for (i=0; i < cnt; i++,st++)            /* put on screen raw */
  110.             if (*st == 27 || *st > 126)
  111.                 {
  112.                 sprintf((char *)tw->parsedat,"<%d>",*st);
  113.                 VSwrite(tw->vs,(char *)tw->parsedat,strlen((char *)tw->parsedat));    /* send to virtual screen */
  114.                 }
  115.             else
  116.                 VSwrite(tw->vs,(char *) st,1);        /* BYU LSC */
  117.         }
  118.     else
  119.         {
  120.  
  121. /*
  122. *  traverse string, looking for any special characters which indicate that
  123. *  we need to change modes.
  124. */
  125.     while (st < mark) 
  126.         {
  127.         switch (tw->telstate)
  128.             {
  129.             case GS:
  130.             case ESCFOUND:
  131.                 if (tw->tektype >= 0) {    /* we'll allow the TEK */
  132.                     if ((*st == 12) || (tw->telstate == GS)) {    /* esc-FF */
  133.                         if ((*st == 12) && 
  134.                             ((tw->termstate == VTEKTYPE) || (!tw->tekclear))) {
  135.                             if (tw->termstate == VTEKTYPE)
  136.                                 putln("Entering Tek mode");
  137.                             else if (tw->curgraph > -1)
  138.                                 detachGraphics(tw->curgraph);
  139.  
  140.                             if (tw->curgraph <=  -1) {        // No current TEK window
  141.                                 temptw = VGnewwin(TEK_DEVICE_WINDOW,tw->vs);
  142.  
  143.                                 if (temptw > -1) {
  144.                                     Str255    scratchPstring;
  145.                                     
  146.                                     tw->curgraph = temptw;
  147.     
  148.                                     VGgiveinfo(temptw);
  149.                                     GetWTitle(tw->wind, scratchPstring);
  150.                                     PtoCstr(scratchPstring);
  151.                                     RGattach(temptw,tw->vs,(char *)scratchPstring, tw->tektype);
  152.                                 }
  153.                                 else
  154.                                     tw->telstate = TS_NORM;  // Can't create TEK window
  155.                             }
  156.  
  157.                             if (tw->telstate != TS_NORM)
  158.                                 tw->termstate = TEKTYPE;
  159.                         }
  160.  
  161.                         if (tw->telstate == GS) {
  162.                             st++;
  163.                             VGwrite(tw->curgraph,"\035",1);
  164.                         }
  165.                         else if (tw->telstate != TS_NORM)
  166.                             VGwrite(tw->curgraph,"\037\033\014",3);
  167.  
  168.                         tw->telstate = TS_NORM;
  169.                         break;
  170.                     } // FF or GS
  171.                 } // tw->tektype >= 0
  172.     
  173.                 if (*st == '^')    {            /* ESC- ^ */
  174.                     tw->termstate = RASTYPE;
  175.                     tw->telstate = TS_NORM;
  176.                     VRwrite("\033^",2);        /* Put it through */
  177.                     orig = ++st;
  178.                     break;
  179.                 }
  180.                 
  181.                 if (tw->termstate == TEKTYPE)
  182.                     VGwrite(tw->curgraph,"\033",1);
  183.                 else if (tw->termstate  == RASTYPE)
  184.                     VRwrite("\033",1);
  185.                 else
  186.                     VSwrite(tw->vs,"\033",1);    /* send the missing ESC */
  187.                 tw->telstate = TS_NORM;
  188.                 break;
  189.  
  190.  
  191. /*------------------------------------------------------------------------------*
  192.  *     IACFOUND:  This is the start of the Telnet option negotiation.  If Telnet    *
  193.  *    gets an IAC character, then negotiation data follows, and is ready to be    *
  194.  *     parsed.                                                                     *
  195.  *------------------------------------------------------------------------------*/
  196.             case IACFOUND:         /* telnet option negotiation- START */
  197.                 if (*st == TEL_IAC) {    /* real data = 255 */
  198.                     orig = st;            // MP: translation mod (break will make it miss
  199.                                         // this assignment later on in the case, Jim!)
  200.                     st++;                /* real 255 will get sent */
  201.                     tw->telstate = TS_NORM;
  202.                     break;
  203.                     }
  204.                 else {
  205.                     switch (*st++) {
  206.                         case TEL_EOF:        /* BYU LSC */
  207.                         case TEL_EL:                /* thanx Quincey!!! */
  208.                         case TEL_EC:
  209.                         case TEL_AYT:
  210.                         case TEL_AO:
  211.                         case TEL_IP:
  212.                         case TEL_BREAK:
  213.                         case TEL_DM:
  214.                         case TEL_NOP:
  215.                         case TEL_SE:
  216.                         case TEL_GA:
  217.             #ifdef OPTS_DEBUG
  218.                             sprintf(munger,"RECV: %s",telstates[tw->telstate]);
  219.                             opts_debug_print(munger); 
  220.             #endif
  221.                             tw->telstate = TS_NORM;
  222.                             orig=st;
  223.                             break;
  224.  
  225.                         case TEL_DOTEL:
  226.                             tw->telstate = TS_DO;
  227.                             orig = st;
  228.                             break;
  229.  
  230.                         case TEL_WILLTEL:
  231.                             tw->telstate = TS_WILL;
  232.                             orig = st;
  233.                             break;
  234.  
  235.                         case TEL_DONTTEL:
  236.                             tw->telstate = TS_DONT;
  237.                             orig = st;
  238.                             break;
  239.  
  240.                         case TEL_WONTTEL:
  241.                             tw->telstate = TS_WONT;
  242.                             orig = st;
  243.                             break;
  244.  
  245.             /*------------------------------------------------------------------------------*
  246.              *     SUBNEGOTIATION -- If there is an SB token found, then Telnet needs to do     *
  247.              *    some subnegotiating.  The subnegotiation data follows, and needs to be put    *
  248.              *    somewhere safe.  Make sure and update the state, so that we know that        *
  249.              *    Telnet is doing some subnegotiations and not just horsing around            *
  250.              *------------------------------------------------------------------------------*/
  251.                         case TEL_SB:
  252.                             tw->telstate = TS_SB;        /* Guess what I'm doing... */
  253.                             orig=st;
  254.                             tw->parseIndex = 0;        /* No data yet! Clear any possible garbage */
  255.                             break;
  256.                             
  257.                         default:        // Means we got IAC <xx> where xx isn't recognized
  258.                             orig = st;
  259.                             tw->telstate = TS_NORM;
  260. #ifdef OPTS_DEBUG
  261.                             sprintf(munger,"RECVD: IAC %c",*(st-1));
  262.                             opts_debug_print(munger);
  263. #endif                            
  264.                             break;
  265.                     }    // switch (*st++)    
  266.                 } // else from it (*st == TEL_IAC)
  267.             break; // case IACFOUND
  268.  
  269.             case TS_DO:
  270.                 telnet_do(tw, *st++);
  271.                 orig = st;
  272.                 tw->telstate = TS_NORM;
  273.                 break;
  274.  
  275.             case TS_DONT:
  276.                 telnet_dont(tw, *st++);
  277.                 orig = st;
  278.                 tw->telstate = TS_NORM;
  279.                 break;
  280.  
  281.             case TS_WILL:
  282.                 telnet_will(tw, *st++);
  283.                 orig = st;
  284.                 tw->telstate = TS_NORM;
  285.                 break;
  286.  
  287.             case TS_WONT:
  288.                 telnet_wont(tw, *st++);
  289.                 orig = st;
  290.                 tw->telstate = TS_NORM;
  291.                 break;
  292.             
  293.             case TS_SB:
  294.                 if (*st == TEL_IAC) 
  295.                 {
  296.                     st++;
  297.                     if (*st == TEL_SE) //subnegotiation over 
  298.                     {
  299.                         st++;
  300.                         process_suboption(tw, st, mark);
  301.                         orig = st;
  302.                         tw->telstate = TS_NORM;
  303.                     }    
  304.                     else
  305.                     {
  306.                         if (*st == TEL_IAC) //doubled IAC
  307.                             tw->parsedat[tw->parseIndex++] = *st++;
  308.                         else
  309.                         {    //process this, then go IAC found
  310.                             
  311.                             tw->parsedat[tw->parseIndex++] = TEL_IAC; //why do we add this to 
  312.                             tw->parsedat[tw->parseIndex++] = *st;     //the parsedat?   We don't 
  313.                             process_suboption(tw, st, mark);        //need it for the options
  314.                             tw->substat = IACFOUND;
  315.                         }
  316.                     }
  317.                 }
  318.                 else     // Collect subnegotiation data
  319.                     tw->parsedat[tw->parseIndex++] = *st++;
  320.                 break;
  321.                                         
  322.             default:
  323.                 tw->telstate = TS_NORM;
  324.                 break;
  325.         } // switch(tw->telstate)
  326.  
  327. /*
  328. * quick scan of the remaining string, skip chars while they are
  329. * uninteresting
  330. */
  331.         if (tw->telstate == TS_NORM) {
  332. /*
  333. *  skip along as fast as possible until an interesting character is found
  334. */
  335.  
  336.             if (!tw->eightbit) {                                            /* BYU 2.4.10 */
  337.                 while (st < mark) {                                            /* BYU 2.4.10 */
  338.                     if (*st == IAC)                                         /* BYU 2.4.10 */
  339.                         break;                                                /* BYU 2.4.10 */
  340.                     else {                                                    /* BYU 2.4.10 */
  341.                         *st &= 0x7f;                                         /* BYU 2.4.10 */
  342.                         if (*st == ESC  || *st == GS)                         /* BYU 2.4.10 */
  343.                             break;                                            /* BYU 2.4.10 */
  344.                         st++;                                                /* BYU 2.4.10 */
  345.                 }    }                                                        /* BYU 2.4.10 */
  346.             } else                                                             /* BYU 2.4.10 */
  347.                 while (st < mark && *st != ESC  && *st < 255 && *st != GS)     // MP: translation mod
  348.                     st++;                                                     /* BYU 2.4.10 */
  349. /*
  350. *  send the string where it belongs
  351. */
  352.             if (!tw->timing) {
  353.                 if (tw->termstate == TEKTYPE) {
  354.                     short i;
  355.                     
  356.                     i = VGwrite( tw->curgraph,(char *) orig,  st-orig);    /* BYU LSC */
  357.                     if (i < (st - orig)) {
  358.                         detachGraphics(tw->curgraph);
  359.                         st = orig + i;
  360.                         }
  361.                     }
  362.                 else if (tw->termstate == RASTYPE) {
  363.                     short i;
  364.                     
  365.                     i= VRwrite((char *) orig, st-orig);        /* BYU LSC */
  366.                     if (i <(st-orig)) {
  367.                         tw->termstate = VTEKTYPE;
  368.                         st = orig +i;                /* Next char to parse */
  369.                         }
  370.                     }
  371.                 else 
  372.                     VSwrite( tw->vs,(char *) orig,st-orig);    /* BYU LSC - send to virtual VT102 */
  373.                 }
  374.  
  375.             orig = st;                /* forget what we have sent already */
  376.  
  377.             if (st < mark)
  378.                 switch (*st) {
  379.                     case TEL_IAC:            /* telnet IAC */
  380.                         tw->telstate = IACFOUND;
  381.                         st++;
  382.                         break;
  383.                     case GS:
  384.                         if (tw->telstate != GS) {
  385.                             tw->telstate = GS;
  386.                             }
  387.                         else
  388.                             tw->telstate = TS_NORM;
  389.                         st++;
  390.                         break;
  391.                         
  392.                     case ESC:            /* ESCape code */
  393.                         if (st == mark-1 || *(st+1) == 12 || *(st+1) == '^' ) {
  394.                             tw->telstate = ESCFOUND;
  395.                         }
  396.                         st++;            /* strip or accept ESC char */
  397.                         break;
  398.     
  399.                     default:
  400.                         if (*st++ > 127) {
  401.                             if (st==mark)                            /*new addition */
  402.                                 VSwrite(tw->vs,(char *) orig,1);    /* BYU LSC */
  403.                              }
  404.                         break;
  405.                 }    // switch(*st)
  406.             } // tw->telstate == TS_NORM
  407.     } // while (st < mark)
  408.     } // tw->termstate != DUMBTYPE
  409.     
  410. //    ProfilerSetStatus(false);
  411.     
  412. } /* parse */
  413.  
  414. void    SendNAWSinfo(WindRec *s, short horiz, short vert)
  415. {
  416.     char            blah[20];
  417.     unsigned char    height, width;
  418.  
  419.     height = vert & 0xff;
  420.     width = horiz & 0xff;
  421.     
  422.     /* 931112, ragge, NADA, KTH, ugly patch to not send IAC as window size  */
  423.     if(height == 0xFF) height = 0xFE;
  424.     if(width == 0xFF) width = 0xFE;
  425.  
  426.     netpush (s->port);
  427.  
  428. /* NCSA: syntax for command is:  IAC SB NAWS widthHI widthLO heightHI heightLO IAC SE */
  429.  
  430.     netwrite(s->port,"\377\372\037\000",4);
  431.     sprintf(blah,"%c\000", width);
  432.     netwrite(s->port,blah,2);
  433.     sprintf(blah,"%c\377\360", height);
  434.     netwrite(s->port,blah,3);
  435.     opts_debug_print("SENT: IAC SB NAWS <data> IAC SE");        
  436. }
  437.  
  438. /*
  439.  * Implementation specific Kerberos routines
  440.  */
  441.  
  442.  
  443. /*
  444.  * getcname
  445.  * Return a pointer to the cannonical host name
  446.  */
  447. static char    *getcname (WindRec *tw)
  448. {
  449.     char *cp;
  450.     static char *b, buf[100];
  451.  
  452.     cp = 0;
  453.     if (tw->cannon[0])
  454.         cp = tw->cannon;
  455.  
  456. //    Doing the following is bad because we disposed of our init params!
  457. //    else if ((*(*(ConnInitParams **)(tw->myInitParams))->session)->hostname)
  458. //        cp = (char *)(*(*(ConnInitParams **)(tw->myInitParams))->session)->hostname;
  459.  
  460.     /* make a local copy to avoid locking handles */
  461.     if (cp) {
  462.         b = buf;        
  463.         while (*cp)
  464.             *b++ = *cp++;            
  465.         *b++ = '\0';
  466.         return buf;
  467.     }
  468.  
  469.     return cp;
  470. }
  471.  
  472.  
  473. /*
  474.  * encryptStatechange
  475.  * Called when the encryption state changes
  476.  */
  477. #define kOurHit    32
  478. static    void encryptStatechange (struct WindRec *tw)
  479. {
  480.     MyWDEFPatch(zoomDocProc, tw->wind, wDraw, kOurHit);
  481. }
  482.  
  483. void    telnet_send_initial_options(WindRec *tw)
  484. {
  485.     if (tw->authenticate) {
  486.         send_will(tw->port, OPT_AUTHENTICATION);
  487.         (tw->myopts)[OPT_AUTHENTICATION-MHOPTS_BASE] = 1;
  488.  
  489.         if (tw->encrypt) {
  490.             send_will(tw->port, OPT_ENCRYPT);        /* will encrypt */
  491.             (tw->myopts)[OPT_ENCRYPT-MHOPTS_BASE] = 1;
  492.         }
  493.     }
  494.  
  495.     send_do(tw->port, N_ECHO);        // Do ECHO
  496.     tw->echo = 1;
  497.  
  498.     send_do(tw->port, N_SGA);        // Do SGA
  499.     tw->Usga=1;
  500.     
  501.     send_wont(tw->port, N_XDISPLOC);
  502.     
  503.     send_will(tw->port, N_NAWS);
  504.  
  505. }
  506.     
  507. static    void    process_suboption(struct WindRec *tw, unsigned char *start, unsigned char *end)
  508. {    
  509.     unsigned long    sendlength;
  510.     unsigned char    sendbuffer[1500];
  511.     short            s;
  512.     char            IACSB[] = { TEL_IAC, TEL_SB, 0, 0};
  513.     char            IACSE[] = { TEL_IAC, TEL_SE};
  514.  
  515.     switch(tw->parsedat[0]) {
  516.     /*------------------------------------------------------------------------------*
  517.     *     SUBNegotiate Termtype:  send the term type data now                            *
  518.     *------------------------------------------------------------------------------*/
  519.         case N_TERMTYP:            
  520.             if (tw->parsedat[1]==1) {
  521.                 char s[60], termtmp[40];
  522.                 BlockMove(tw->answerback, termtmp, 32);
  523.                 PtoCstr((StringPtr)termtmp);
  524. #ifdef OPTS_DEBUG
  525.                 sprintf(munger,"RECV: SB TERMINAL-TYPE SEND\r\nSEND: SB TERMINAL-TYPE IS %s\r\n",termtmp);
  526.                 opts_debug_print(munger); 
  527. #endif
  528.                 IACSB[2] = '\030';
  529.                 IACSB[3] = 0;
  530.                 netpush(tw->port);
  531.                 netwrite(tw->port,IACSB,4);
  532.                 netpush(tw->port);
  533.                 sprintf(s,"%s%c%c",termtmp, TEL_IAC, TEL_SE);
  534.                 netwrite(tw->port, s, strlen(s));
  535.                 }
  536.             break;
  537.                 
  538. /*------------------------------------------------------------------------------*
  539. *     SUBNegotiate ENCRYPTION:                                                     *
  540. *------------------------------------------------------------------------------*/
  541.             case N_ENCRYPT:
  542.                 sendlength = sizeof(sendbuffer);
  543.                 s = encrypt_suboption((tnParams **)&tw->aedata, tw->parsedat,
  544.                                       tw->parseIndex,
  545.                                       sendbuffer, &sendlength, getcname(tw), 
  546.                                       tw->hisopts[OPT_ENCRYPT - MHOPTS_BASE], 
  547.                                       tw->myopts[OPT_ENCRYPT - MHOPTS_BASE]);
  548.                 netportencryptstate(tw->port, (Ptr)tw->aedata);
  549.                 encryptStatechange(tw);
  550.  
  551.                 /*
  552.                  * If we turned on encryption, we must decrypt the rest of the buffer.
  553.                  */
  554.                 if (s == TNREP_START_DECRYPT) {
  555.                     unsigned char *cp = start;
  556.                     while (cp < end) {
  557.                         *cp = decrypt((tnParams *)tw->aedata, (long)(*cp));
  558.                         cp++;
  559.                     }
  560.                 }
  561.  
  562.                 if (sizeof(sendbuffer) - sendlength)
  563.                     netwrite(tw->port, sendbuffer, sizeof(sendbuffer)-sendlength);
  564.                 
  565.                 /*
  566.                  * transfer the encrypting flag here, after the buffer 
  567.                  * with encrypt-start has gone out.
  568.                  */
  569.                 if (((tnParams *)tw->aedata)->startencrypting) {
  570.                     ((tnParams *)tw->aedata)->startencrypting = false;
  571.                     ((tnParams *)tw->aedata)->encrypting = true;
  572.                     }
  573.             break;
  574.                 
  575.     /*------------------------------------------------------------------------------*
  576.     *     SUBNegotiate Authentication:  send the authentication data now                 *
  577.     *------------------------------------------------------------------------------*/
  578.         case N_AUTHENTICATION:            
  579.             sendlength = sizeof(sendbuffer);
  580.             auth_suboption((tnParams **)&tw->aedata, tw->parsedat,
  581.                            tw->parseIndex,
  582.                            sendbuffer, &sendlength, getcname(tw), 
  583.                            tw->hisopts[OPT_ENCRYPT-MHOPTS_BASE], 
  584.                            tw->myopts[OPT_ENCRYPT-MHOPTS_BASE]);
  585.             if (sizeof(sendbuffer) - sendlength) {
  586.                 netwrite(tw->port, sendbuffer, sizeof(sendbuffer)-sendlength);
  587.                 }
  588.             break;
  589.             
  590.     /*------------------------------------------------------------------------------*
  591.     *     SUBNegotiate Linemode:  set up local characters, modes, and such            *
  592.     *------------------------------------------------------------------------------*/
  593.         case N_LINEMODE:
  594.             linemode_suboption(tw);
  595.             break;
  596.  
  597.     /*------------------------------------------------------------------------------*
  598.     *     SUBNegotiate REMOTE_FLOW_CONTROL:  determine whether we control flow, and   *
  599.     *                                       what restarts flow                         *
  600.     *------------------------------------------------------------------------------*/
  601.         case N_REMOTEFLOW:
  602.             switch (tw->parsedat[1])
  603.             {
  604.  
  605.                 case FLOW_OFF:
  606. #ifdef OPTS_DEBUG
  607.                     sprintf(munger,"RECV: SB REMOTE_FLOW FLOW_OFF");
  608.                     opts_debug_print(munger); 
  609. #endif
  610.                     tw->allow_flow = FALSE;
  611.                 break;
  612.                 
  613.                 case FLOW_ON:
  614. #ifdef OPTS_DEBUG
  615.                     sprintf(munger,"RECV: SB REMOTE_FLOW FLOW_ON");
  616.                     opts_debug_print(munger); 
  617. #endif    
  618.                     tw->allow_flow = TRUE;
  619.                 break;
  620.                 
  621.                 case FLOW_RESTART_ANY:
  622. #ifdef OPTS_DEBUG
  623.                     sprintf(munger,"RECV: SB REMOTE_FLOW FLOW_RESTART_ANY");
  624.                     opts_debug_print(munger); 
  625. #endif    
  626.                     tw->restart_any_flow = TRUE;
  627.                 break;
  628.                 
  629.                 case FLOW_RESTART_XON:
  630. #ifdef OPTS_DEBUG
  631.                     sprintf(munger,"RECV: SB REMOTE_FLOW FLOW_RESTART_XON");
  632.                     opts_debug_print(munger); 
  633. #endif    
  634.                     tw->restart_any_flow = FALSE;
  635.                 break;
  636.                 
  637.                 default:
  638.                 break;    
  639.             }
  640.         
  641.         default: //dont know this subnegotiation!!
  642.             break;
  643.     }
  644. }            
  645.  
  646. static    void    telnet_do(struct WindRec *tw, short option)
  647. {
  648. #ifdef OPTS_DEBUG
  649.     sprintf(munger,"RECV: %s %s",telstates[TEL_DOTEL-TEL_SE],teloptions[option]);
  650.     opts_debug_print(munger); 
  651. #endif
  652.     switch(option) {
  653.         case  N_SGA:        /* Sure we'll supress GA */
  654.             if (!tw->Isga) {
  655.                 tw->Isga=1;
  656.                 send_will(tw->port, N_SGA);
  657.                 }
  658.             break;
  659.         
  660.         case N_TERMTYP:        /* And we'll even tell you about ourselves */
  661.             if (!tw->Ittype) {
  662.                 tw->Ittype=1;
  663.                 send_will(tw->port, N_TERMTYP);
  664.                 }
  665.             break;
  666.  
  667.         case  N_NAWS:            /* NCSA: sure, I like changing the window size! */
  668.             tw->naws =1;        /* NCSA: this session is now NAWS */
  669.             send_will(tw->port, N_NAWS);
  670.  
  671.             SendNAWSinfo(tw, VSmaxwidth(tw->vs) + 1, VSgetlines(tw->vs));
  672. #ifdef OPTS_DEBUG
  673.             opts_debug_print("SENT: IAC TEL_SB N_NAWS <data> IAC TEL_SE"); 
  674. #endif
  675.             break;                                            /* NCSA */
  676.  
  677.         case N_LINEMODE:  /* Sure I'll do line mode... */
  678.             if (tw->lineAllow)  
  679.             {
  680.                 send_will(tw->port, N_LINEMODE);
  681.                 doLinemode(tw);
  682.             }
  683.             else
  684.                 send_wont(tw->port, N_LINEMODE);
  685.             break;
  686.  
  687.         case N_AUTHENTICATION:        /* do auth */
  688.             if (!tw->myopts[OPT_AUTHENTICATION-MHOPTS_BASE]) {
  689.                 if (tw->authenticate) {
  690.                     (tw->myopts)[OPT_AUTHENTICATION-MHOPTS_BASE] = 1;
  691.                     send_will(tw->port, N_AUTHENTICATION);
  692.                     }
  693.                 else {
  694.                     send_wont(tw->port, N_AUTHENTICATION);
  695.                     }
  696.             }
  697.             break;
  698.  
  699.         case N_ENCRYPT:             /* do encrypt */
  700.             if (!tw->myopts[OPT_ENCRYPT-MHOPTS_BASE]) {
  701.                 if (tw->encrypt) {
  702.                     (tw->myopts)[OPT_ENCRYPT-MHOPTS_BASE] = 1;
  703.                     send_will(tw->port, N_ENCRYPT);
  704.                 } else {
  705.                     send_wont(tw->port, N_ENCRYPT);
  706.                 }
  707.             }
  708.             break;
  709.         
  710.         case N_REMOTEFLOW:
  711.             if (!tw->remote_flow)
  712.             {
  713.                 tw->remote_flow = TRUE;
  714.                 send_will(tw->port, option); 
  715.             }            
  716.             break;
  717.             
  718.         default:                /* But, we won't do .... */
  719.             send_wont(tw->port, option);
  720.             break;
  721.         }
  722. }
  723.  
  724. static    void    telnet_dont(struct WindRec *tw, short option)
  725. {
  726. #ifdef OPTS_DEBUG
  727.     sprintf(munger,"RECV: %s %s",telstates[TEL_DONTTEL-TEL_SE],teloptions[option]);
  728.     opts_debug_print(munger); 
  729. #endif
  730.  
  731.     switch (option) {
  732.         case N_ENCRYPT:                    /* dont encrypt */
  733.         case N_AUTHENTICATION:            /* dont authenticate */
  734.             tw->myopts[option - MHOPTS_BASE] = 0;
  735.             send_wont(tw->port, option);
  736.             break;
  737.         case N_LINEMODE:  /* Ok. turn it off if its on */
  738.             if (tw->lmode)  
  739.             {
  740.                 send_wont(tw->port, N_LINEMODE);
  741.                 if (tw->kblen > 0)
  742.                 {
  743.                     netpush(tw->port);
  744.                     netwrite(tw->port, tw->kbbuf, tw->kblen);
  745.                 }    
  746.                 tw->lmode = 0;
  747.                 tw->lmodeBits = 0;
  748.                 tw->litNext = 0;
  749.             }
  750.             break;
  751.  
  752.  
  753.     }
  754. }
  755.  
  756. static    void    telnet_will(struct WindRec *tw, short option)
  757. {
  758. #ifdef OPTS_DEBUG
  759.     sprintf(munger,"RECV: %s %s",telstates[TEL_WILLTEL-TEL_SE],teloptions[option]);
  760.     opts_debug_print(munger); 
  761. #endif
  762.     switch(option) 
  763.         {
  764.         case N_ECHO:             /* Echo on the other end*/
  765. #ifdef    OPTS_DEBUG
  766.             if (!tw->echo)
  767.                 opts_debug_print("tw->echo is False.");
  768. #endif
  769.             if (!tw->echo)
  770.                 break;
  771.             tw->echo = 0;    /* Ok, in that case they can echo... */
  772.             changeport(scrn,scrn);
  773.             send_do(tw->port, N_ECHO);
  774.             break;
  775.         
  776.         case N_SGA:                /* Supress GA */
  777. #ifdef    OPTS_DEBUG
  778.             if (tw->Usga)
  779.                 opts_debug_print("tw->Usga is True.");
  780. #endif
  781.             if (tw->Usga)
  782.                 break;
  783.             tw->Usga = 1;    /* Go Ahead and supress GA */
  784.             send_do(tw->port, N_SGA);
  785.             break;
  786.         
  787.         case N_TIMING:                /* Timing Mark */
  788.             tw->timing = 0;
  789.             break;
  790.         
  791.         case N_AUTHENTICATION:        /* will auth */
  792.             if (!tw->hisopts[OPT_AUTHENTICATION-MHOPTS_BASE]) {
  793.                 if (tw->authenticate) {
  794.                     (tw->hisopts)[OPT_AUTHENTICATION-MHOPTS_BASE] = 1;
  795.                     send_do(tw->port, N_AUTHENTICATION);
  796.                     }
  797.                 else {
  798.                     send_dont(tw->port, N_AUTHENTICATION);
  799.                 }
  800.             }
  801.             break;
  802.  
  803.         case N_ENCRYPT:             /* will encrypt */
  804.             if (!tw->hisopts[OPT_ENCRYPT-MHOPTS_BASE]) {
  805.                 if (tw->encrypt) {
  806.                     (tw->hisopts)[OPT_ENCRYPT-MHOPTS_BASE] = 1;
  807.                     send_do(tw->port, N_ENCRYPT);
  808.                 } else {
  809.                     send_dont(tw->port, N_ENCRYPT);
  810.                 }
  811.             }
  812.             break;
  813.  
  814.         case N_REMOTEFLOW:     /* they want to toggle flow control */
  815.             if (!tw->remote_flow)
  816.             {
  817.                 tw->remote_flow = 1;
  818. #ifdef    OPTS_DEBUG
  819.                 opts_debug_print("tw->remote_flow is True.");
  820. #endif
  821.                 send_do(tw->port, N_REMOTEFLOW);
  822.             }
  823.  
  824.         default:
  825.             send_dont(tw->port, option);
  826.         }
  827. }
  828.  
  829. static    void    telnet_wont(struct WindRec *tw, short option)
  830. {
  831. #ifdef OPTS_DEBUG
  832.     sprintf(munger,"RECV: %s %s",telstates[TEL_WONTTEL-TEL_SE],teloptions[option]);
  833.     opts_debug_print(munger); 
  834. #endif
  835.     switch(option) 
  836.         {         /* which option? */
  837.         case N_ECHO:             /* echo */
  838.             if (tw->echo)
  839.                 break;
  840.             tw->echo = 1;    /* Ok, I will echo if I have to... */
  841.             changeport(scrn,scrn);
  842.             send_dont(tw->port,N_ECHO);
  843.             break;
  844.         
  845.         case N_SGA:
  846.             if (!tw->Usga)
  847.                 break;
  848.             tw->Usga = 0;
  849.                send_dont(tw->port,N_SGA);
  850.             break;
  851.         
  852.         case N_TIMING:                /* Timing Mark */
  853.             tw->timing = 0;
  854.             break;
  855.         
  856.         case N_ENCRYPT:                    /* wont encrypt */
  857.         case N_AUTHENTICATION:            /* wont authenticate */
  858.             tw->hisopts[option-MHOPTS_BASE] = 0;
  859.             send_dont(tw->port, option);
  860.             break;
  861.  
  862.         default:
  863.             break;
  864.         }
  865. }
  866.  
  867. void    send_do(short port, short option)
  868. {
  869.     char    data[] = { IAC, TEL_DOTEL, 0};
  870.     
  871.     data[2] = option;
  872.     netpush(port);
  873.     netwrite(port, data, 3);
  874. #ifdef OPTS_DEBUG
  875.     sprintf(munger,"SENT: DO %s",teloptions[option]);
  876.     opts_debug_print(munger); 
  877. #endif
  878. }
  879.  
  880. void    send_dont(short port, short option)
  881. {
  882.     char    data[] = { IAC, TEL_DONTTEL, 0};
  883.  
  884.     data[2] = option;
  885.     netpush(port);
  886.     netwrite(port, data, 3);
  887. #ifdef OPTS_DEBUG
  888.     sprintf(munger,"SENT: DONT %s",teloptions[option]);
  889.     opts_debug_print(munger); 
  890. #endif
  891. }
  892.  
  893. static    void    send_will(short port, short option)
  894. {
  895.     char    data[] = { IAC, TEL_WILLTEL, 0};
  896.  
  897.     data[2] = option;
  898.     netpush(port);
  899.     netwrite(port, data, 3);
  900. #ifdef OPTS_DEBUG
  901.     sprintf(munger,"SENT: WILL %s",teloptions[option]);
  902.     opts_debug_print(munger); 
  903. #endif
  904. }
  905.  
  906. static    void    send_wont(short port, short option)
  907. {
  908.     char    data[] = { IAC, TEL_WONTTEL, 0};
  909.     
  910.     data[2] = option;
  911.     netpush(port);
  912.     netwrite(port, data, 3);
  913. #ifdef OPTS_DEBUG
  914.     sprintf(munger,"SENT: WONT %s",teloptions[option]);
  915.     opts_debug_print(munger); 
  916. #endif
  917. }